package com.cqhfan.userservice.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqhfan.cache.annotations.MultiLevelCache;
import com.cqhfan.cache.utils.CacheUtil;
import com.cqhfan.core.domain.dto.PageDTO;
import com.cqhfan.core.domain.query.PageQuery;
import com.cqhfan.core.enums.FollowStatusEnum;
import com.cqhfan.core.utils.UserContext;
import com.cqhfan.pojo.user.po.Follow;
import com.cqhfan.pojo.user.vo.UserFriendVO;
import com.cqhfan.pojo.user.vo.UserProfileVO;
import com.cqhfan.redis.constants.RedisConstants;
import com.cqhfan.userservice.mapper.UserMapper;
import com.cqhfan.userservice.service.FollowService;
import com.cqhfan.userservice.service.UserService;
import com.cqhfan.core.exceptions.BizException;
import com.cqhfan.pojo.user.po.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 眭传洪
 * @create 2025-07-21 22:02
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final CacheUtil cacheUtil;

    private final StringRedisTemplate stringRedisTemplate;

    private final FollowService followService;

    @Override
    public User getByUserName(String userName) {
        if (StrUtil.isBlank(userName)) {
            throw new BizException("根据用户名获取用户失败，原因：用户名为空");
        }
        return lambdaQuery().eq(User::getUserName, userName).one();
    }

    @Override
    public User getByUserPhone(String phone) {
        if (StrUtil.isBlank(phone)) {
            throw new BizException("根据手机号获取用户失败，原因：手机号为空");
        }
        return lambdaQuery().eq(User::getPhone, phone).one();
    }

    @Override
    @MultiLevelCache(key = "#userId", prefix = "user:id")
    public User getByUserId(Long userId) {
        return getById(userId);
    }

    @Override
    public UserProfileVO profile(Long userId) {
        boolean isSelf = false;
        if (userId == null) {
            isSelf = true;
            // 代表查看的是自己的主页，直接获取从ThreadLocal中获取
            userId = UserContext.getUser();
        }
        User user = getByUserId(userId);
        if (user == null) {
            throw new BizException("用户信息为空");
        }
        if (user.getIfPrivate()) {
            // 私密账号，直接返回null
            return null;
        }

        // 转换vo
        UserProfileVO result = new UserProfileVO();
        result.setId(userId);
        result.setNickName(user.getNickName());
        result.setDescription(user.getDescription());
        result.setSex(user.getSex());
        result.setAddress(user.getAddress());
        result.setDouyinNumber(user.getDouyinNumber());
        result.setAvatar(user.getAvatar());
        result.setCreateTime(user.getCreateTime());
        // 从redis获取几个数量数据
        String key = RedisConstants.UserProfileInfo.KEY + userId;
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(key);
        result.setFansNumber(Integer.parseInt(entries.get(RedisConstants.UserProfileInfo.FANS_HASH_KEY).toString()));
        result.setFollowNumber(Integer.parseInt(entries.get(RedisConstants.UserProfileInfo.FOLLOW_HASH_KEY).toString()));
        if (isSelf) {
            // 是自己的主页才显示朋友个个数
            result.setFriendNumber(Integer.parseInt(entries.get(RedisConstants.UserProfileInfo.FRIEND_HASH_KEY).toString()));
        } else {
            // 不是自己的主页，不显示朋友数量，然后需要设置是否关注
            String followKey = RedisConstants.FOLLOW.KEY + userId;
            Long myUserId = UserContext.getUser();
            Boolean heFollowMeFlag = stringRedisTemplate.opsForSet().isMember(followKey, myUserId.toString());
            followKey = RedisConstants.FOLLOW.KEY + myUserId;
            Boolean iFollowHeFlag = stringRedisTemplate.opsForSet().isMember(followKey, userId.toString());
            if (BooleanUtil.and(heFollowMeFlag, iFollowHeFlag)) {
                result.setFollowStatus(FollowStatusEnum.FRIEND.getValue());
            } else if (BooleanUtil.isTrue(heFollowMeFlag) && BooleanUtil.isFalse(iFollowHeFlag)) {
                result.setFollowStatus(FollowStatusEnum.FANS.getValue());
            } else if (BooleanUtil.isTrue(iFollowHeFlag) && BooleanUtil.isFalse(heFollowMeFlag)) {
                result.setFollowStatus(FollowStatusEnum.FOLLOW.getValue());
            } else {
                result.setFollowStatus(FollowStatusEnum.ALL_NOT.getValue());
            }
        }
        result.setLikedNumber(Integer.parseInt(entries.get(RedisConstants.UserProfileInfo.LIKED_HASH_KEY).toString()));
        return result;
    }

    @Override
    public void updateUserInfo(User user) {
        Long douyinNumber = user.getDouyinNumber();
        if (douyinNumber != null) {
            // 如果是更新的抖音号，则180天不允许更新，先判断redis是否存在这个key 不存在则还需要添加一个标识到redis
            String key = RedisConstants.DOUYIN_NUMBER_UPDATE_KEY_PREFIX + user.getId();
            Boolean exists = stringRedisTemplate.hasKey(key);
            if (BooleanUtil.isTrue(exists)) {
                throw new BizException("抖音号180天只能更新一次");
            }

            // 添加标识
            stringRedisTemplate.opsForValue().set(key, RedisConstants.NULL_VALUE,
                    RedisConstants.DOUYIN_NUMBER_UPDATE_INTERVAL, TimeUnit.DAYS);
        }
        // 更新数据库
        updateById(user);

        // 删除缓存
        String cacheKey = RedisConstants.CACHE_KEY_PREFIX + "user:id:" + user.getId();
        cacheUtil.removeCache(cacheKey);
    }

    @Override
    public Long saveUser(User user) {
        save(user);
        return user.getId();
    }

    @Override
    public PageDTO<UserFriendVO> pageFriend(PageQuery query) {
        Integer pageNum = query.getPageNum();
        Integer pageSize = query.getPageSize();
        Long userId = UserContext.getUser();

        // 获取我的朋友
        Page<Follow> page = followService.pageFriend(new Page<>(pageNum, pageSize), userId);
        List<Follow> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return PageDTO.empty();
        }

        // 获取对应的用户信息
        Set<Long> friendUserIds = records.stream().map(Follow::getFollowUserId).collect(Collectors.toSet());
        List<User> users = listByIds(friendUserIds);
        if (CollUtil.isEmpty(users)) {
            throw new BizException("用户信息为空");
        }
        Map<Long, User> userMap = users.stream().collect(Collectors.toMap(User::getId, u -> u));

        // 组装vo
        List<UserFriendVO> result = new ArrayList<>(records.size());
        for (Follow record : records) {
            User user = userMap.get(record.getFollowUserId());
            if (user == null) {
                continue;
            }
            UserFriendVO vo = new UserFriendVO();
            vo.setUserId(user.getId());
            vo.setNickName(user.getNickName());
            vo.setAvatar(user.getAvatar());
            result.add(vo);
        }
        return PageDTO.of(page.getPages(), page.getTotal(), result);
    }
}
